﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Samples.ServiceHosting.StorageClient;
using Ciripescu_WebRole.Entities;
using System.Data.Services.Client;

namespace Ciripescu_WebRole.BL
{
    public class CiripMessageManager
    {
        public static int NbOfCiripsPerPage = Properties.Settings.Default.NbOfCiripsPerPage;
        public CiripMessageManager()
        {
            m_svcContext             = new MyServiceContext();
            m_svcContext.RetryPolicy = RetryPolicies.RetryN(3, TimeSpan.FromSeconds(1));
        }

        public IEnumerable<CiripMessage> DoQuery(IQueryable<CiripMessage> q)
        {
            TableStorageDataServiceQuery<CiripMessage> query = new TableStorageDataServiceQuery<CiripMessage>(q as DataServiceQuery<CiripMessage>);
            IEnumerable<CiripMessage> queryResults = query.ExecuteAllWithRetries();
            return queryResults;
        }

        public IEnumerable<CiripMessage> DoQuery(IQueryable<CiripMessage> q, int count)
        {            
            IEnumerable<CiripMessage> queryResults = q.Take(count);
            return queryResults;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="forUserName">PartitionKey</param>
        /// <param name="rowKey">RowKey</param>
        /// <returns></returns>
        public CiripMessage GetSingleMessage(string forUserName, string rowKey)
        {
            try
            {
                return (DoQuery(from c in m_svcContext.CiripMessage where c.PartitionKey == forUserName && c.RowKey == rowKey select c)).Single();
            }
            catch (InvalidOperationException)
            {
                // no items to return
                return null;
            }
            catch (Exception e)
            {
                Utils.WriteLog(EventLogName.Error, e.ToString());
                return null;
            }
        }

        public CiripMessage GetSingle(string partitionKey, string rowKey)
        {
            return GetSingleMessage(partitionKey, rowKey);
        }

        /// <summary>
        /// Return Messages for a certain username
        /// </summary>
        /// <param name="forUuserName"></param>
        /// <param name="startFromRowKey"></param>
        /// <param name="type">0 for Direct Message (Inbox), 1 for Reply, 2 for Sent Message (Outbox - Sent)</param>
        /// <returns></returns>
        public List<CiripMessage> GetForUserName(string forUuserName, int type, string startFromRowKey)
        {
            IQueryable<CiripMessage> results = null;
            if (string.IsNullOrEmpty(startFromRowKey))
                results = from c in m_svcContext.CiripMessage where c.PartitionKey == forUuserName && c.MessageType == type select c;
            else
                results = from c in m_svcContext.CiripMessage where c.PartitionKey == forUuserName && c.MessageType == type && c.RowKey.CompareTo(startFromRowKey) > 0 select c;
            IEnumerable<CiripMessage> res = DoQuery(results, NbOfCiripsPerPage);
            List<CiripMessage> lis = new List<CiripMessage>();
            try
            {
                lis = res.ToList();
            }
            catch (Exception ex)
            {
            }
            return lis;
        }

        /// <summary>
        /// Convert a CiripMessage to a Cirip
        /// </summary>
        /// <param name="m"></param>
        /// <param name="Type">0 for Direct Message (Inbox), 1 for Reply, 2 for Sent Message (Outbox - Sent)</param>
        /// <returns></returns>
        public Cirip CiripMessageToCirip(CiripMessage m, int Type)
        {
            string link = null;
            Cirip c = null;
            if (Type == 1) // Reply
            {
                //link = "@<a href='/profile.aspx?userName=" + m.getTo() + "' class='mylink'>" + m.getTo() + "</a>: ";
                c = new Cirip(m.From, m.Content, m.getTo(), m.InReplyToId);
            }
            else if (Type == 0) //Inbox
            {
                //link = "<a href='/profile.aspx?userName=" + m.From + "' class='mylink'>" + m.From + "</a>: ";
                link = "<a href='/u/" + m.From + "' class='mylink'>" + m.From + "</a>: ";
                c = new Cirip(m.getTo(), link + m.Content, m.From, string.Empty);
            }
            else // Type  == 2 Outbox
            {                
                //link = "<a href='/profile.aspx?userName=" + m.From + "' class='mylink'>" + m.From + "</a>: ";
                link = "<a href='/u/" + m.From + "' class='mylink'>" + m.From + "</a>: ";
                // TO and FROM are reversed for Outbox (Sent) messages!
                c = new Cirip(m.getTo(), link + m.Content, string.Empty, string.Empty);
            }
            c.RowKey = m.RowKey; // the generated rowkey will have a timestamp with this very second, we need the original RowKey
            c.Timestamp = m.Timestamp;
            c.TimePosted = m.TimePosted;
            return c;
        }
        /// <summary>
        /// Conver of list of CiripMessage to a list of Cirip
        /// </summary>
        /// <param name="mlist"></param>
        /// <param name="Type">0 for Direct Message (Inbox), 1 for Reply, 2 for Sent Message (Outbox - Sent)</param>
        /// <returns></returns>
        public List<Cirip> CiripMessageListToCiripList(List<CiripMessage> mlist, int Type)
        {
            List<Cirip> ret = new List<Cirip>();
            foreach (CiripMessage m in mlist)
                ret.Add(CiripMessageToCirip(m,Type));
            return ret;
        }

         public void Delete(CiripMessage itemToDelete)
        {
            m_svcContext.DeleteObject(itemToDelete);
            m_svcContext.SaveChanges();
        }

        public void DeleteWithoutQ(CiripMessage itemToDelete)
        {
            m_svcContext.AttachTo(m_svcContext.CiripMessageTableName, itemToDelete, "*");
            Delete(itemToDelete);
        }

        /// <summary>
        /// Updates an existing item from the tables.
        /// </summary>
        /// <param name="item"></param>
        public void Save(CiripMessage item)
        {
            m_svcContext.UpdateObject(item);
            m_svcContext.SaveChanges();
        }

        /// <summary>
        /// Insert a new item in the tables.
        /// </summary>
        /// <param name="newItem"></param>
        public void Insert(CiripMessage newItem)
        {
            m_svcContext.AddObject(m_svcContext.CiripMessageTableName, newItem);
            m_svcContext.SaveChanges();
        }

        

        #region Private Methods

        private MyServiceContext m_svcContext = null;
        
        #endregion
    }
}
